package cxm.lib.sys;

import cxm.lib.util.MyLog;

public abstract class AsyncStartMachine extends StartMachine implements Runnable {
	private boolean isRunning = false;
	Thread thread = null;
	
	public void setIsRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}

	@Override
	public void run() {
		Thread.currentThread().setName(this.getClass().getName());
		if (!this.onBeforeRun()) {
			MyLog.Log(MyLog.Level.Error, "Cannot prepare run");
			return;
		}
		
		while (this.isRunning) {
			this.onRunOnce();
		}
		
		this.onAfterRun();
	}

	@Override
	protected final void onStart() throws StartMachineException {
		this.thread = new Thread(this);
		this.isRunning = true;
		this.thread.start();
		
		// wait for a while
		try {
			Thread.sleep(500, 0);
		} catch (Exception e) {
			MyLog.Log(MyLog.Level.Error, "Cannot wait for " + e);
		}
	}

	@Override
	protected final void onStop() {
		this.isRunning = false;
		this.onBeforeStop();
		try {
			MyLog.Log(MyLog.Level.Debug, "Before join thread: " + this.thread);
			this.thread.join();
		} catch (Exception e) {
			MyLog.Log(MyLog.Level.Error, "Cannot join thread: " + e);
		}
		this.thread = null;
		this.onAfterStop();
	}
	
	protected abstract void onRunOnce();
	protected boolean onBeforeRun() {
		return true;
	}
	protected void onAfterRun() {
		
	}
	protected void onBeforeStop() {
		// remain empty
	}
	protected void onAfterStop() {
		
	}
}
